﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms.Design;
using System.Windows.Forms;
using System.ComponentModel.Design;
using System.ComponentModel;
using System.Drawing.Design;
using System.Drawing;
using System.Collections;
using DevExpress.Utils;

namespace ProgNetComponentsDx.Controls.Design.Designers
{
    public class MultiGroupControlDesigner : ParentControlDesigner
    {
        #region Fields
        private DesignerActionListCollection _actionLists;
        private DesignerVerbCollection _verbs;
        private MultiGroupControl MultiGroup;
        #endregion

        public override bool ParticipatesWithSnapLines
        {
            get
            {
                bool result;
                MultiGroupPanelDesigner designer;

                designer = this.GetSelectedMultiGroupPanelDesigner();

                if (designer != null)
                    result = designer.ParticipatesWithSnapLines;
                else
                    result = true;

                return result;
            }
        }
        public override DesignerVerbCollection Verbs
        {
            get
            {
                if (_verbs == null)
                {
                    _verbs = new DesignerVerbCollection();
                    _verbs.Add(new DesignerVerb("Add Group", (sender, e) => { AddGroup(); }) { Description = "Add a new MultiGroupPanel to the parent control." });
                    _verbs.Add(new DesignerVerb("Collapse All", (sender, e) => { MultiGroup.CollapseAll(); }) { Description = "Collapses all groups." });
                    _verbs.Add(new DesignerVerb("Expand All", (sender, e) => { MultiGroup.ExpandAll(); }) { Description = "Expands all groups." });
                }

                return _verbs;
            }
        }
        public override void Initialize(IComponent component)
        {
            ISelectionService selectionService;
            IComponentChangeService changeService;
            MultiGroup = component as MultiGroupControl;

            base.Initialize(component);

            // attach an event so we can be notified when the selected components in the host change
            selectionService = (ISelectionService)this.GetService(typeof(ISelectionService));
            if (selectionService != null)
                selectionService.SelectionChanged += this.selectionService_SelectionChanged;

            // attach an event to notify us of when a component has been modified
            changeService = (IComponentChangeService)this.GetService(typeof(IComponentChangeService));
            if (changeService != null)
                changeService.ComponentChanged += this.componentChangeService_ComponentChanged;

        }
        public override void InitializeNewComponent(IDictionary defaultValues)
        {
            base.InitializeNewComponent(defaultValues);
            this.AddGroup();
        }
        public override SelectionRules SelectionRules
        {
            get
            {
                SelectionRules r = base.SelectionRules;

                if (MultiGroup != null && MultiGroup.AutoSize)
                {
                    //r &= ~System.Windows.Forms.Design.SelectionRules.BottomSizeable;
                   // r &= ~System.Windows.Forms.Design.SelectionRules.LeftSizeable;
                   // r &= ~System.Windows.Forms.Design.SelectionRules.RightSizeable;
                   // r &= ~System.Windows.Forms.Design.SelectionRules.TopSizeable;
                    return r;
                }
                return r;
            }
        }
        protected override IComponent[] CreateToolCore(ToolboxItem tool, int x, int y, int width, int height, bool hasLocation, bool hasSize)
        {
            MultiGroupControl control;
            IDesignerHost host;

            control = this.MultiGroup;
            var c = control.GetChildAtPoint(new Point(x, y));
            var c2 = control.GetChildAtPoint(control.PointToClient(new Point(x, y)));
            // prevent controls from being created directly on the TabList
            if (control.FocusedGroup == null)
                throw new ArgumentException(string.Format("Cannot add control '{0}', no group is selected.", tool.DisplayName));

            host = (IDesignerHost)this.GetService(typeof(IDesignerHost));
            if (host != null)
            {
                ParentControlDesigner childDesigner;
                childDesigner = (ParentControlDesigner)host.GetDesigner(control.FocusedGroup);
                ParentControlDesigner.InvokeCreateTool(childDesigner, tool);
            }
            return null;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ISelectionService selectionService;
                IComponentChangeService changeService;

                // deatch all the events we hooked into earlier
                selectionService = (ISelectionService)this.GetService(typeof(ISelectionService));
                if (selectionService != null)
                    selectionService.SelectionChanged -= this.selectionService_SelectionChanged;

                changeService = (IComponentChangeService)this.GetService(typeof(IComponentChangeService));
                if (changeService != null)
                    changeService.ComponentChanged -= this.componentChangeService_ComponentChanged;
            }

            base.Dispose(disposing);
        }

        protected override bool GetHitTest(Point point)
        {
            bool result;
            Point location;
            location = this.MultiGroup.PointToClient(point);
            result = this.MultiGroup.HitTest(location) != null;
            return result;
        }
        protected override void OnPaintAdornments(PaintEventArgs pe)
        {
            base.OnPaintAdornments(pe);
            ControlPaint.DrawFocusRectangle(pe.Graphics, this.Control.ClientRectangle);
        }
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case 0x7b: // WM_CONTEXTMENU
                    Point position;

                    // For some reason the context menu is no longer displayed when right clicking the control
                    // By hooking into the WM_CONTEXTMENU context message we can display the menu ourselves

                    position = Cursor.Position;

                    this.OnContextMenu(position.X, position.Y);
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }

        public override bool CanParent(Control control)
        {
            return control is MultiGroupPanel;
        }
        
        private MultiGroupPanel GetComponentOwner(object component)
        {
            MultiGroupPanel result;

            if (component is Control)
            {
                Control parent;

                parent = (Control)component;
                while (parent != null && !(parent is MultiGroupPanel))
                    parent = parent.Parent;

                result = (MultiGroupPanel)parent;
            }
            else
                result = null;

            return result;
        }
        private MultiGroupPanelDesigner GetSelectedMultiGroupPanelDesigner()
        {
            MultiGroupPanelDesigner designer;
            MultiGroupPanel selectedPanel;

            selectedPanel = this.MultiGroup.FocusedGroup;
            designer = null;

            if (selectedPanel != null)
            {
                IDesignerHost host;

                host = (IDesignerHost)this.GetService(typeof(IDesignerHost));
                if (host != null)
                    designer = host.GetDesigner(selectedPanel) as MultiGroupPanelDesigner;
            }

            return designer;
        }
       
        private void AddGroup()
        {
            IDesignerHost host = (IDesignerHost)this.GetService(typeof(IDesignerHost));
            if (host != null)
            {
                using (DesignerTransaction transaction = host.CreateTransaction(string.Format("Add TabListPage to '{0}'", MultiGroup.Name)))
                {
                    try
                    {
                        MultiGroupPanel panel;
                        MemberDescriptor controlsProperty;

                        panel = (MultiGroupPanel)host.CreateComponent(typeof(MultiGroupPanel));
                        controlsProperty = TypeDescriptor.GetProperties(MultiGroup)["Controls"];
                        this.RaiseComponentChanging(controlsProperty);
                        panel.Text = panel.Name;
                        MultiGroup.Controls.Add(panel);
                        panel.BringToFront();
                        this.RaiseComponentChanged(controlsProperty, null, null);
                        transaction.Commit();
                    }
                    catch
                    {
                        transaction.Cancel();
                        throw;
                    }
                }
            }
        }
        
        public override System.ComponentModel.Design.DesignerActionListCollection ActionLists
        {
            get
            {
                if (this._actionLists != null)
                    return this._actionLists;
                this._actionLists = this.CreateActionList();
                return base.ActionLists;
            }
        }
        private DesignerActionListCollection CreateActionList()
        {
            DesignerActionListCollection collection = new DesignerActionListCollection();
            collection.Add(new MultiGroupControlActionList(this));
            return collection;
        }

        void componentChangeService_ComponentChanged(object sender, ComponentChangedEventArgs e)
        {
        }

        void selectionService_SelectionChanged(object sender, EventArgs e)
        {
            ISelectionService service;

            service = (ISelectionService)this.GetService(typeof(ISelectionService));
            if (service != null)
            {
                MultiGroupControl control;

                control = this.MultiGroup;
                foreach (object component in service.GetSelectedComponents())
                {
                    MultiGroupPanel ownedPage;

                    // check to see if one of the selected controls is hosted on a TabListPage. If it is, 
                    // activate the page. This means, if for example, you select a control via the
                    // IDE's properties window, the relavent TabListPage will be activated

                    ownedPage = this.GetComponentOwner(component);
                    if (ownedPage != null && ownedPage.Parent == control)
                    {
                        ownedPage.Focus();
                        break;
                    }
                }
            }
        }


        private class MultiGroupControlActionList : DesignerActionList
        {
            MultiGroupControlDesigner designer;
            public MultiGroupControlActionList(MultiGroupControlDesigner designer)
                : base(designer.Component)
            {
                this.designer = designer;
            }
            public override DesignerActionItemCollection GetSortedActionItems()
            {
                DesignerActionItemCollection col = new DesignerActionItemCollection();
                col.Add(new DesignerActionPropertyItem("AutoSize", "AutoSize"));
                col.Add(new DesignerActionHeaderItem("Groups"));
                col.Add(new DesignerActionMethodItem(this, "AddGroup", "Add Group", "Groups"));
                col.Add(new DesignerActionMethodItem(this, "CollapseAll", "Collapse All", "Groups"));
                col.Add(new DesignerActionMethodItem(this, "ExpandAll", "Expand All", "Groups"));

                col.Add(new DesignerActionHeaderItem("Groups Properties", "Groups"));
                col.Add(new DesignerActionPropertyItem("GroupsCollapseDirection", "Groups Collapse Direction", "Groups Properties"));
                col.Add(new DesignerActionPropertyItem("GroupsLocation", "Groups Location", "Groups Properties"));
                col.Add(new DesignerActionPropertyItem("GroupsCollapseMode", "Groups Collapse Mode", "Groups Properties"));
                return col;
            }
            public bool AutoSize
            {
                get { return designer.MultiGroup.AutoSize; }
                set { designer.MultiGroup.SetPropertyValueWithPropertyDescriptor("AutoSize", value); }
            }
            public Locations GroupsCollapseDirection
            {
                get { return designer.MultiGroup.GroupsCollapseDirection; }
                set { designer.MultiGroup.SetPropertyValueWithPropertyDescriptor("GroupsCollapseDirection", value); }
            }
            public Locations GroupsLocation
            {
                get { return designer.MultiGroup.GroupsLocation; }
                set { designer.MultiGroup.SetPropertyValueWithPropertyDescriptor("GroupsLocation", value); }
            }
            public GroupCollapseModes GroupsCollapseMode
            {
                get { return designer.MultiGroup.GroupsCollapseMode; }
                set { designer.MultiGroup.SetPropertyValueWithPropertyDescriptor("GroupsCollapseMode", value); }
            }

            void AddGroup()
            {
                designer.AddGroup();
            }
            void CollapseAll()
            {
                designer.MultiGroup.CollapseAll();
            }
            void ExpandAll()
            {
                designer.MultiGroup.ExpandAll();
            }
        }
    }
}
